home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1997 December
/
MACPOWER-1997-12.ISO.7z
/
MACPOWER-1997-12.ISO
/
AMUG
/
PROGRAMMING
/
Raven 1.2.sit
/
Raven 1.2
/
Source
/
Foundation
/
Common
/
ZStringUtils.cpp
< prev
next >
Wrap
Text File
|
1997-08-07
|
13KB
|
574 lines
/*
* File: ZStringUtils.cpp
* Summary: Misc string utilities
* Written by: Jesse Jones
*
* Copyright ゥ 1996-1997 Jesse Jones.
* For conditions of distribution and use, see copyright notice in ZTypes.h
*
* Change History (most recent first):
*
* <3> 8/05/97 JDJ Added LoadAppString and LoadRavenString.
* <2> 7/27/97 JDJ Added StripTrailing.
* <1> 8/09/96 JDJ Created (from ZMiscUtils)
*/
#include <ZStringUtils.h>
#include <CType.h>
#include <Map.h>
#include <Resources.h>
#include <String.h>
#include <TextUtils.h>
#include <ZConstants.h>
#include <ZDebug.h>
#include <ZExceptions.h>
#include <ZUnitTest.h>
//-----------------------------------
// Types
//
#pragma options align=mac68k
struct SXEntry {
short code;
Str255 str;
};
struct SXTable { // 'STRX' resource format
short numEntries;
SXEntry entries[1];
};
typedef map<string, string, less<string>, allocator<string> > ZStringMap;
#pragma options align=reset
//---------------------------------------------------------------
//
// NextEntry
//
// We have to do this grody pointer arithmetic because ResEdit only
// saves the characters that are actually used by the string.
//
//---------------------------------------------------------------
static SXEntry* NextEntry(SXEntry* entry)
{
Byte* ptr = (Byte *) entry;
ptr += entry->str[0] + 3;
if ((long) ptr & 1) // ResEdit will add a pad byte for odd strings.
ptr++;
return (SXEntry *) ptr;
}
//---------------------------------------------------------------
//
// LoadStringMap
//
//---------------------------------------------------------------
static void LoadStringMap(ResID id, ZStringMap& mapping)
{
Handle table = GetResource('StrM', id);
if (table != nil) {
HLockHi(table);
short count = *((short*) (*table));
const unsigned char* nextStr = ((const unsigned char*) (*table)) + sizeof(short);
while (count--) {
const unsigned char* inStr = nextStr;
nextStr += nextStr[0] + 1;
const unsigned char* outStr = nextStr;
nextStr += nextStr[0] + 1;
ZStringMap::value_type value(PStrToStr(inStr), PStrToStr(outStr));
mapping.insert(value);
}
ReleaseResource(table);
}
}
#pragma mark -
// ===================================================================================
// Conversions
// ===================================================================================
//---------------------------------------------------------------
//
// PStrToStr
//
//---------------------------------------------------------------
string PStrToStr(const unsigned char* pStr)
{
ASSERT(pStr != nil);
return string((char *) pStr+1, *pStr);
}
//---------------------------------------------------------------
//
// StrToPStr
//
//---------------------------------------------------------------
unsigned char* StrToPStr(const string& cStr)
{
ASSERT(cStr.length() < 256);
const short kTempStrings = 8;
static short currentString = 0;
static Str255 strings[kTempStrings];
currentString = (short) ((currentString + 1) % kTempStrings);
ulong length = cStr.length() < 256 ? cStr.length() : 255;
BlockMoveData(cStr.c_str(), &strings[currentString][1], length);
strings[currentString][0] = (Byte) length;
return strings[currentString];
}
//---------------------------------------------------------------
//
// IDToStr
//
//---------------------------------------------------------------
const char* IDToStr(IDType id)
{
ASSERT(sizeof(ulong) == 4);
const short kTempStrings = 4;
static short currentString = 0;
static char strings[kTempStrings][5];
currentString = (short) ((currentString + 1) % kTempStrings);
BlockMoveData(&id, &strings[currentString][0], 4UL);
strings[currentString][4] = '¥0';
return strings[currentString];
}
//---------------------------------------------------------------
//
// StrToID
//
//---------------------------------------------------------------
IDType StrToID(const string& str)
{
ASSERT(str.length() == 4);
IDType type;
BlockMoveData(str.c_str(), &type, 4UL);
return type;
}
#pragma mark -
// ===================================================================================
// Loading
// ===================================================================================
//---------------------------------------------------------------
//
// LoadString
//
//---------------------------------------------------------------
string LoadString(ResID id)
{
string result;
Handle strH = GetResource('STR ', id);
ThrowIfResFail(strH);
HLock(strH);
try {
result = PStrToStr((unsigned char*) *strH);
} catch (...) {
HUnlock(strH);
throw;
}
ReleaseResource(strH);
return result;
}
//---------------------------------------------------------------
//
// LoadIndString
//
//---------------------------------------------------------------
string LoadIndString(ResID strList, int index)
{
ASSERT(index >= 1);
Str255 str;
GetIndString(str, strList, (short) index);
return PStrToStr(str);
}
//---------------------------------------------------------------
//
// LoadAppString
//
//---------------------------------------------------------------
string LoadAppString(const string& inStr)
{
static ZStringMap mapping;
static bool inited = false;
if (!inited) {
LoadStringMap(256, mapping);
inited = true;
}
string outStr = inStr;
ZStringMap::iterator iter = mapping.find(inStr);
if (iter != mapping.end())
outStr = (*iter).second;
return outStr;
}
//---------------------------------------------------------------
//
// LoadRavenString
//
//---------------------------------------------------------------
string LoadRavenString(const string& inStr)
{
static ZStringMap mapping;
static bool inited = false;
if (!inited) {
LoadStringMap(128, mapping);
inited = true;
}
string outStr = inStr;
ZStringMap::iterator iter = mapping.find(inStr);
if (iter != mapping.end())
outStr = (*iter).second;
return outStr;
}
//---------------------------------------------------------------
//
// LookUpString
//
//---------------------------------------------------------------
string LookUpString(ResID id, int code)
{
string str = "";
SXTable** table = (SXTable **) GetResource('STRX', id);
ThrowIfResFail(table);
HNoPurge((Handle) table);
ThrowIfMemError();
short count = (**table).numEntries;
SXEntry* entry = &((**table).entries[0]);
bool found = false;
while (count > 0 && !found) {
found = entry->code == code;
if (!found) {
entry = NextEntry(entry);
count--;
}
}
if (found) {
str.resize(entry->str[0] + 1UL); // resize the string to the correct length to prevent the string ctor from moving memory
str = PStrToStr(entry->str);
}
HPurge((Handle) table);
return str;
}
#pragma mark -
// ===================================================================================
// Disassembly
// ===================================================================================
//---------------------------------------------------------------
//
// Before
//
//---------------------------------------------------------------
string Before(const string& str, const string& sub)
{
string result;
size_t index = str.find(sub);
if (index != string::npos)
result = str.substr(0, index);
return result;
}
//---------------------------------------------------------------
//
// After
//
//---------------------------------------------------------------
string After(const string& str, const string& sub)
{
string result;
size_t index = str.find(sub);
if (index != string::npos)
result = str.substr(index + sub.length());
return result;
}
//---------------------------------------------------------------
//
// Parse
//
//---------------------------------------------------------------
string Parse(string& str, const string& term)
{
string token;
// Start at the first character not in term.
size_t start = str.find_first_not_of(term);
// Stop at the next occurance of a character in term.
size_t stop = str.find_first_of(term, start + 1);
// If the start is valid return the token.
if (start != string::npos)
token = str.substr(start, stop-start);
// Remove the token from the string.
if (stop != string::npos)
str = str.substr(stop);
else
str.resize(0);
// Remove term chars from the start of the string. (Makes it easier
// to determine when parsing is complete).
str = Strip(str, term);
return token;
}
#pragma mark -
// ===================================================================================
// Misc
// ===================================================================================
//---------------------------------------------------------------
//
// StrToUpperStr
//
//---------------------------------------------------------------
string StrToUpperStr(const string& lowerStr)
{
string upperStr = lowerStr;
for (short i = 0; i < (short) upperStr.length(); i++)
upperStr[i] = (char) toupper(upperStr[i]);
return upperStr;
}
//---------------------------------------------------------------
//
// StrToLowerStr
//
//---------------------------------------------------------------
string StrToLowerStr(const string& upperStr)
{
string lowerStr = upperStr;
for (short i = 0; i < (short) lowerStr.length(); i++)
lowerStr[i] = (char) tolower(lowerStr[i]);
return lowerStr;
}
//---------------------------------------------------------------
//
// Strip
//
//---------------------------------------------------------------
string Strip(const string& str, const string& padding)
{
size_t index = 0;
while (index < str.length() && padding.find(str[index]) != string::npos)
index++;
return str.substr(index);
}
//---------------------------------------------------------------
//
// StripTrailing
//
//---------------------------------------------------------------
string StripTrailing(const string& str, const string& padding)
{
size_t index = 0;
if (!str.empty()) {
index = str.size();
while (index > 1 && padding.find(str[index-1]) != string::npos)
index--;
}
return str.substr(0, index);
}
//---------------------------------------------------------------
//
// Replace
//
//---------------------------------------------------------------
string Replace(const string& inStr, char oldCh, char newCh)
{
string str = inStr;
for (size_t i = 0; i < str.length(); i++)
if (str[i] == oldCh)
str[i] = newCh;
return str;
}
#pragma mark -
// ===================================================================================
// Unit Test
// ===================================================================================
//---------------------------------------------------------------
//
// EqualPStr
//
//---------------------------------------------------------------
#if DEBUG
static bool EqualPStr(unsigned char* s1, unsigned char* s2)
{
ASSERT(s1 != nil);
ASSERT(s2 != nil);
return memcmp(s1, s2, *s1 + 1UL) == 0;
}
#endif // DEBUG
//---------------------------------------------------------------
//
// TestStringUtils
//
//---------------------------------------------------------------
#if DEBUG
static void TestStringUtils()
{
ASSERT(PStrToStr("¥p") == ""); // PStrToStr
ASSERT(PStrToStr("¥ph") == "h");
ASSERT(PStrToStr("¥pHello") == "Hello");
ASSERT(EqualPStr(StrToPStr(""), "¥p")); // StrToPStr
ASSERT(EqualPStr(StrToPStr("h"), "¥ph"));
ASSERT(EqualPStr(StrToPStr("Hello"), "¥pHello"));
ASSERT(strcmp(IDToStr('TEXT'), "TEXT") == 0); // IDToStr
ASSERT(strcmp(IDToStr('????'), "????") == 0);
ASSERT(strcmp(IDToStr('jpg '), "jpg ") == 0);
ASSERT(StrToID("TEXT") == 'TEXT'); // StrToID
ASSERT(StrToID("????") == '????');
ASSERT(StrToID("jpg ") == 'jpg ');
ASSERT(LoadString(131) == "Save File As:"); // LoadString
ASSERT(LoadIndString(132, 1) == "Undo "); // LoadIndString
ASSERT(LookUpString(203, -39) == "end of file");// LookUpString
string str = "semper fi mac";
ASSERT(Before(str, " fi") == "semper"); // Before
ASSERT(Before(str, " qq") == "");
ASSERT(Before(str, "semp") == "");
ASSERT(Before(str, "mac") == "semper fi ");
ASSERT(Before(str, "Mac") == "");
ASSERT(After(str, " fi") == " mac"); // After
ASSERT(After(str, " qq") == "");
ASSERT(After(str, "semp") == "er fi mac");
ASSERT(After(str, "mac") == "");
ASSERT(After(str, "Mac") == "");
ASSERT(Parse(str, " f") == "semper"); // Parse
ASSERT(str == "i mac");
ASSERT(Parse(str, " f") == "i");
ASSERT(str == "mac");
ASSERT(Parse(str, " f") == "mac");
ASSERT(str == "");
str = "e = M*c^2";
ASSERT(StrToUpperStr(str) == "E = M*C^2"); // StrToUpperStr
ASSERT(StrToLowerStr(str) == "e = m*c^2"); // StrToLowerStr
str = " oolong"; // Strip
ASSERT(Strip(str, " ") == "oolong");
ASSERT(Strip(str, " o") == "long");
ASSERT(Strip(str, " l") == "oolong");
ASSERT(Strip(str, "o ") == "long");
ASSERT(Strip(str, "o") == " oolong");
ASSERT(Replace("hello", 'l', 'k') == "hekko"); // Replace
ASSERT(Replace("hekko", 'h', 'k') == "kekko");
ASSERT(Replace("kekko", 'o', 'k') == "kekkk");
ASSERT(Replace("kekkk", 'e', 'k') == "kkkkk");
ASSERT(Replace("kkkkk", 'k', 'j') == "jjjjj");
ASSERT(Replace("h", 'h', 'k') == "k");
ASSERT(Replace("", 'h', 'k') == "");
TRACE("Completed str utils test.¥n¥n");
}
static TUnitTestRegistrar sStringReg("String Utils", TestStringUtils);
#endif // DEBUG